/**
 * @Title: XMLUtils.java
 * @Package com.lemon.utils
 * @Description: (一句话阐述):
 * @author Ran_cc
 * @date 2018年10月22日
 * @version V1.0
 */
package com.lemon.utils;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.LinkedList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.core.util.JsonUtils;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.alibaba.fastjson.JSONObject;
import com.lemon.conf.MyException;

import de.odysseus.staxon.json.JsonXMLConfig;
import de.odysseus.staxon.json.JsonXMLConfigBuilder;
import de.odysseus.staxon.json.JsonXMLInputFactory;
import de.odysseus.staxon.xml.util.PrettyXMLEventWriter;

/**
 * <p>
 * Title: XMLUtils
 * </p>
 * <p>
 * Description:
 * </p>
 * <p>
 * Company:
 * </p>
 * 
 * @author Ran_cc
 * @date 2018年10月22日
 * @版本 V 1.0
 */
public class XMLUtils {

	//	public static final String setUrl = "src/main/resources/SetXml.xml";
	public static final String setUrl = "/SetXml.xml";

	public static void main(String[] args) {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		Element theBook = null , theElem = null , root = null;
		try {
			factory.setIgnoringElementContentWhitespace(true);

			DocumentBuilder db = factory.newDocumentBuilder();
			//			Document xmldoc = db.parse();
			Document xmldoc = db.parse(new File(setUrl));
			root = xmldoc.getDocumentElement();

			//--- 新建一本书开始 ----

			/*
			 * theBook = xmldoc.createElement("ench");
			 * theElem = xmldoc.createElement("name");
			 * theElem.setTextContent("新书");
			 * theBook.appendChild(theElem);
			 * theElem = xmldoc.createElement("price");
			 * theElem.setTextContent("2000");
			 * theBook.appendChild(theElem);
			 * theElem = xmldoc.createElement("memo");
			 * theElem.setTextContent("新书的更好看。");
			 * theBook.appendChild(theElem);
			 * root.appendChild(theBook);
			 * System.out.println("--- 新建一本书开始 ----");
			 * output(xmldoc);
			 */

			//--- 新建一本书完成 ----
			//--- 下面对《哈里波特》做一些修改。 ----
			//--- 查询找《哈里波特》----

			/*
			 * theBook = (Element) selectSingleNode("/sets/ench" , root);
			 * System.out.println("--- 查询找《哈里波特》 ----");
			 * output(theBook);
			 * //--- 此时修改这本书的价格 -----
			 * theBook.getElementsByTagName("price").item(0).setTextContent("105");//getElementsByTagName 返回的是NodeList，所以要跟上item(0)。另外，getElementsByTagName("price")相当于xpath 的".//price"。
			 * System.out.println("--- 此时修改这本书的价格 ----");
			 */
			//			output(theBook);

			//--- 另外还想加一个属性id，值为B01 ----
			/*
			 * theBook.setAttribute("id" , "B013");
			 * System.out.println("--- 另外还想加一个属性id，值为B01 ----");
			 */
			//			output(theBook);

			//--- 对《哈里波特》修改完成。 ----
			/*
			 * //--- 要用id属性删除《三国演义》这本书 ----
			 * theBook = (Element) selectSingleNode("/books/book[@id='B02']" , root);
			 * System.out.println("--- 要用id属性删除《三国演义》这本书 ----");
			 * output(theBook);
			 * theBook.getParentNode().removeChild(theBook);
			 * System.out.println("--- 删除后的ＸＭＬ ----");
			 * output(xmldoc);
			 * //--- 再将所有价格低于10的书删除 ----
			 * NodeList someBooks = selectNodes("/books/book[price<10]" , root);
			 * System.out.println("--- 再将所有价格低于10的书删除 ---");
			 * System.out.println("--- 符合条件的书有　" + someBooks.getLength() + "本。 ---");
			 * for (int i = 0; i < someBooks.getLength(); i++) {
			 * someBooks.item(i).getParentNode().removeChild(someBooks.item(i));
			 * }
			 */
			//			output(xmldoc);
			//saveXml(setUrl , xmldoc);

			/*
			 * String string = getXmlToJSONString(setUrl);
			 * String string2 = JSONToXML(string);
			 * saveXml(string2 , setUrl);
			 */

			String minAmount = "1";
			String serviceCharge = "10";
			String enchInfo = "123456789";

			String jsonString = XMLUtils.getXmlToJSONString(XMLUtils.setUrl);
			System.out.println(jsonString);
			JSONObject parse = (JSONObject) JSONObject.parse(jsonString);
			JSONObject js = parse.getJSONObject("sets");
			JSONObject js2 = js.getJSONObject("enchenchashment");
			js2.put("minAmount" , minAmount);
			js2.put("serviceCharge" , serviceCharge);
			js2.put("enchInfo" , enchInfo);
			js.put("enchenchashment" , js2);
			parse.put("sets" , js);
			System.out.println(parse.toString());
			XMLUtils.saveXml(parse.toString() , XMLUtils.setUrl);
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * <b>Description:<blockquote> 获取xml文件内容并转成jsonString
	 * </blockquote></b>
	 * 
	 * @Title: getXmlToJSONString
	 * @return
	 * @author Ran_cc
	 * @date 2018年10月22日
	 */
	public static String getXmlToJSONString(String url) {
		try {
			InputStream in = JsonUtils.class.getResourceAsStream(url);  //此方法只能读取 resources目录下的文件
			//			Resource resource = new ClassPathResource("SetXml.xml");
			//			File file = resource.getFile();
			//			InputStream in = new FileInputStream(file);    // 通过对象多态性，进行实例化
			String xml = IOUtils.toString(in);
			//org.json.JSONObject xmlJSONObj = XML.toJSONObject(xml);
			//			System.out.println(xmlJSONObj.toString());
			JSONObject js = xml2JSON(xml.getBytes());
			in.close();
			return js.toJSONString();
		} catch (Exception e) {
			MyException.writeErr(e , "");
		}
		return null;
	}

	/**
	 * <b>Description:<blockquote> 获取xml文件内容并转成jsonString
	 * </blockquote></b>
	 * 
	 * @Title: getXmlToJSONString
	 * @return
	 * @author Ran_cc
	 * @date 2018年10月22日
	 */
	public static String JSONToXML(String json) {
		try {
			StringReader input = new StringReader(json);
			StringWriter output = new StringWriter();
			JsonXMLConfig config = new JsonXMLConfigBuilder().multiplePI(false).repairingNamespaces(false).build();
			try {
				XMLEventReader reader = new JsonXMLInputFactory(config).createXMLEventReader(input);
				XMLEventWriter writer = XMLOutputFactory.newInstance().createXMLEventWriter(output);
				writer = new PrettyXMLEventWriter(writer);
				writer.add(reader);
				reader.close();
				writer.flush();
				writer.close();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					output.close();
					output.flush();
					input.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			return output.toString();
		} catch (Exception e) {
			MyException.writeErr(e , "");
		}
		return null;
	}

	/**
	 * <b>Description:<blockquote> 将json 转成xml 并修改文件
	 * </blockquote></b>
	 * 
	 * @Title: saveXml
	 * @param json
	 * @author Ran_cc
	 * @throws IOException
	 * @date 2018年10月22日
	 */
	public static void saveXml(String json , String url) throws IOException {
		InputStream is = null;
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			json = JSONToXML(json);
			is = new ByteArrayInputStream(json.getBytes());
			DocumentBuilder db = factory.newDocumentBuilder();
			Document xmldoc = db.parse(is);
			saveXml(url , xmldoc);
		} catch (Exception e) {
			MyException.writeErr(e , "");
		} finally {
			if (null != is) {
				is.close();
			}
		}
	}

	public static void output(Node node) {//将node的XML字符串输出到控制台
		TransformerFactory transFactory = TransformerFactory.newInstance();
		try {
			Transformer transformer = transFactory.newTransformer();
			transformer.setOutputProperty("encoding" , "utf-8");
			transformer.setOutputProperty("indent" , "yes");
			DOMSource source = new DOMSource();
			source.setNode(node);
			StreamResult result = new StreamResult();
			result.setOutputStream(System.out);

			transformer.transform(source , result);
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}
	}

	public static Node selectSingleNode(String express , Object source) {//查找节点，并返回第一个符合条件节点
		Node result = null;
		XPathFactory xpathFactory = XPathFactory.newInstance();
		XPath xpath = xpathFactory.newXPath();
		try {
			result = (Node) xpath.evaluate(express , source , XPathConstants.NODE);
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}

		return result;
	}

	public static NodeList selectNodes(String express , Object source) {//查找节点，返回符合条件的节点集。
		NodeList result = null;
		XPathFactory xpathFactory = XPathFactory.newInstance();
		XPath xpath = xpathFactory.newXPath();
		try {
			result = (NodeList) xpath.evaluate(express , source , XPathConstants.NODESET);
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}

		return result;
	}

	public static void saveXml(String fileName , Document doc) {//将Document输出到文件
		TransformerFactory transFactory = TransformerFactory.newInstance();
		try {
			Transformer transformer = transFactory.newTransformer();
			transformer.setOutputProperty("indent" , "yes");
			DOMSource source = new DOMSource();
			source.setNode(doc);
			StreamResult result = new StreamResult();
			Resource resource = new ClassPathResource(fileName);
			File file = resource.getFile();
			FileOutputStream stream = new FileOutputStream(file);
			result.setOutputStream(stream);
			transformer.transform(source , result);

			try {
				stream.flush();
				stream.close();
			} catch (IOException e) {
				MyException.writeErr(e , "");
			}

		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			MyException.writeErr(e , "");
		}
	}

	////用ali 的转 
	public static JSONObject xml2JSON(byte[] xml) throws JDOMException , IOException {
		JSONObject json = new JSONObject();
		InputStream is = new ByteArrayInputStream(xml);
		SAXBuilder sb = new SAXBuilder();
		org.jdom2.Document doc = sb.build(is);

		org.jdom2.Element root = doc.getRootElement();
		json.put(root.getName() , iterateElement(root));
		return json;
	}

	private static JSONObject iterateElement(org.jdom2.Element element) {
		List node = element.getChildren();
		org.jdom2.Element et = null;
		JSONObject obj = new JSONObject();
		List list = null;
		for (int i = 0; i < node.size(); i++) {
			list = new LinkedList();
			et = (org.jdom2.Element) node.get(i);
			if (et.getTextTrim().equals("")) {
				if (et.getChildren().size() == 0)
					continue;
				if (obj.containsKey(et.getName())) {
					list = (List) obj.get(et.getName());
				}
				list.add(iterateElement(et));
				obj.put(et.getName() , list.get(0));
			} else {
				if (obj.containsKey(et.getName())) {
					list = (List) obj.get(et.getName());
				}
				list.add(et.getTextTrim());
				obj.put(et.getName() , list.get(0));
			}
		}
		return obj;
	}
}
